package com.motu.monstercity.server.game.verticle;

import com.motu.monstercity.module.common.redis.RedisKey;
import com.motu.monstercity.module.common.servermanager.ServerInfo;
import com.motu.monstercity.module.common.servermanager.ServerManager;
import com.motu.monstercity.module.common.utility.EventBusConstant;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.mysql.MysqlClient;
import com.motu.vertx.module.utility.mysql.MysqlTool;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

//更新服务器redis数据到数据库中
public class MonitorVerticle extends AbstractVerticle {
	public final static Logger logger = LoggerFactory.getLogger(MonitorVerticle.class);

	public static final long MONITOR_PERIODIC_DELAY_TIME = 60000L; //MonitorVerticle执行周期时间

	public void start(Promise<Void> future) throws Exception {
		logger.info("SaveOnlineNumVerticle start !!!!!!!!!!!!!");
		vertx.setPeriodic(MONITOR_PERIODIC_DELAY_TIME, handler -> {
			long time = TimeUtils.getCurTime();

			// 通知monitor_gate数据更新
			String address = EventBusConstant.getAddress(EventBusConstant.MONITOR_SAVEDATA);
			EventBus eventBus = MainService.getVertx().eventBus();
			JsonObject obj = new JsonObject().put("time", time);
			eventBus.publish(address, obj);

			// 通知player_online数据更新（为了不影响“通知monitor_gate数据更新”，在其之后执行）
			try {
				updatePlayerOnlineData(time);
			} catch (Throwable e) {
				logger.error(Tool.getException(e));
			}

		});
		future.complete();
	}

	/**
	 * 在线数更新
	 */
	private void updatePlayerOnlineData(long time) {
		// X分通知gate写入redis，取上次存储时间的redis数据写入数据库，更新存储时间为X
		// 因为在线数据，一分钟记录一次，由各个gate进程存到相同的redis字段中，因为写入需要时间，所以取前一分钟的数据

		// 通知gate统计和更新player_online数据
		String address2 = EventBusConstant.getAddress(EventBusConstant.MONITOR_SAVEDATA_PLAYERONLINE);
		JsonObject obj2 = new JsonObject().put("time", time);
		EventBus eventBus2 = MainService.getVertx().eventBus();
		eventBus2.publish(address2, obj2);

		// 取上次player_online的时间戳和gate更新的player_online数据
		String updateTimeRedisKey = RedisKey.getMonitorPlayerOnlineUpdateTimeKey();
		// 上次更新时间
		String updateTimeResult = Future.await(RedisTools.get(updateTimeRedisKey));
		// 更新时间戳为这次通知时间
		RedisTools.set(updateTimeRedisKey, String.valueOf(time));
		if (Tool.isEmpty(updateTimeResult)) {
			return;// 第一次或过了很久启动会是没数据的
		}
		long updateTime = Long.parseLong(updateTimeResult);
		if ((time - updateTime) > (Tool.MINUTE * 15)) {
			return;// 上次的数据过期，写入时设置了15分钟过期
		}
		// 取数据
		ConcurrentHashMap<Integer, Integer> playerOnlineMap = new ConcurrentHashMap<>();// key服务器ID，value数量
		String playerOnlineKey = RedisKey.getMonitorPlayerOnlineKey(updateTime);
		JsonObject obj = Future.await(RedisTools.getHashJsonObject(playerOnlineKey));
		if (obj != null) {
			for (Entry<String, Object> entry : obj) {
				playerOnlineMap.put(Integer.parseInt(entry.getKey()), Integer.parseInt(entry.getValue().toString()));
			}
			RedisTools.del(playerOnlineKey);// 清理redis用完的在线数据
		}

		// 写入数据库
		ConcurrentHashMap<Integer, ServerInfo> serverList = ServerManager.getServerList(false);
		StringBuilder playOnlineSqlBuilder = new StringBuilder("INSERT INTO player_online(server_id, num, add_time) VALUES ");
		boolean first = true;
		JsonArray sqlParams = new JsonArray();
		int sumOnlineNum = 0;
		for (ServerInfo serverInfo : serverList.values()) {
			playerOnlineMap.merge(serverInfo.getServerId(), 0, Integer::sum);// 填充服务器ID
			if (first) {
				first = false;
			} else {
				playOnlineSqlBuilder.append(",");
			}
			int num = playerOnlineMap.get(serverInfo.getServerId());
			sumOnlineNum += num;
			playOnlineSqlBuilder.append("(?,?,?)");
			sqlParams.add(serverInfo.getServerId())
					.add(num)
					.add(updateTime);
		}
		playOnlineSqlBuilder.append(";");
		String sql = playOnlineSqlBuilder.toString();
		MysqlTool.queryJsonArrayFromDb(MysqlClient.getServerPool(), sql, sqlParams, h -> {
			if (h.failed()) {
				logger.error(h.cause().getMessage());
			}
		});

		//// 发送其它在线日志
//		List<Integer> serverIdSortList = new ArrayList<>(playerOnlineMap.keySet());
//		serverIdSortList.sort(Integer::compareTo);
//
//		// efun用户在线数据日志
//		if (EfunLogManager.isSendEfunOnlineLog()) {
//			// 因为在线数据，一分钟记录一次，由各个gate进程上报，时间并不统一，所以取前一分钟的数据
//			try {
//				Map<Integer, String[]> efunLogDataMap = new HashMap<>();
//				for (Integer serverId : serverIdSortList) {
//					int num = playerOnlineMap.getOrDefault(serverId, 0);
//					String[] strAry = new String[]{String.valueOf(serverId), String.valueOf(num)};
//					efunLogDataMap.put(serverId, strAry);
//				}
//				EfunLogManager.sendServerOnlineLog(updateTime, efunLogDataMap);
//			} catch (Exception e) {
//				logger.error(Tool.getException(e));
//			}
//		}
//
//		// haoplay用户在线数据日志
//		if (HaoplayManager.isSendOnlineLog() && HaoplayManager.checkOnlineLogInterval(time)) {
//			// 因为在线数据，一分钟记录一次，由各个gate进程上报，时间并不统一，所以取前一分钟的数据
//			// haoplay只需在线总数，X分钟间隔一次
//			try {
//				HaoplayManager.sendServerOnlineLog(time, updateTime, sumOnlineNum);
//			} catch (Exception e) {
//				logger.error(Tool.getException(e));
//			}
//		}
	}

}
